home *** CD-ROM | disk | FTP | other *** search
- /* This is the source to ShrinkToFit, an init that shrinks Think C windows to fit around the
- * current selection. As it exists, it only works for Think C, but it could probably be adapted
- * to your favorite text editor.
- *
- * The way it works:
- * It inserts an JGNEFilter proc. This looks for control-clicks in the zoom box. It
- * diddles the zoom rects to get THC to resize the window appropriately. It also
- * posts an "enter" key to get THC to center the current selection in the window.
- * When the filterproc gets the key event, it restores the zoom rects so that you
- * can zoom normally.
- *
- * Copyright © 1990 Meredith Lesly. All rights reserved
- */
-
- #ifndef _MacTypes_
- #include <MacHeaders>
- #endif
- #include <PE.h>
-
- static Boolean nextEnter; /* Flag to indicate whether to restore the old zoom box */
- static ProcPtr oldProc;
-
- #define MINLINES 7
- #define VMARGIN 24
-
- typedef struct {
- WStateData theUsual;
- Rect oldStdState;
- } ExtWStateData;
-
- void jgneHook();
-
- main()
- {
- long saveA4;
-
- asm {
-
- /* Make globals addressable */
- move.l a4,saveA4
-
- /* Recover and detach myself. I'm already locked. */
- lea main,a0
- move.l a0,a4
- _RecoverHandle
- move.l a0,-(sp)
- _DetachResource
- }
-
- /* Clear a flag */
- nextEnter = FALSE;
-
- /* Stash teh old filter */
- oldProc = JGNEFilter;
- JGNEFilter = (void *)jgneHook;
-
- /* restore a4 */
- asm {
- move.l saveA4,a4
- }
- }
-
- void jgneHook()
- {
- long saveA4;
-
- asm {
- move.l a4,saveA4 ; save a4
- lea main,a4 ; set up for globals
- }
- doIt();
- asm {
- move.l oldProc,a0
- move.l saveA4,a4
- unlk a6
- move.b 4(sp),d0
- jmp (a0)
- }
- }
-
- doIt()
- {
- register EventRecord *ep;
- WindowPtr wPtr;
- short part;
- EvQElPtr q;
-
- asm {
- move.l a1,ep ; rescue eventrecord ptr
- }
- if (nextEnter == TRUE) { /* do we want to fix zoom rects now? */
- ExtWStateData *stateData;
-
- if (ep->what != keyDown)
- goto exit;
- nextEnter = FALSE;
- wPtr = FrontWindow();
- stateData = *(ExtWStateData **)((WindowPeek)FrontWindow())->dataHandle;
- stateData->theUsual.stdState = stateData->oldStdState;
- goto exit;
- }
- else if ((ep->what != mouseDown) || ((ep->modifiers & controlKey) == 0))
- goto exit;
-
- part = FindWindow(ep->where, &wPtr);
- if (part != inZoomIn && part != inZoomOut)
- goto exit;
-
- diddleZoom(wPtr);
- nextEnter = TRUE;
-
- PPostEvent(keyDown, 0x4c03, &q); /* Post the enter key */
- q->evtQModifiers = 0; /* Make sure the modifiers keys are clear! */
-
- exit:
- asm {
- move.l ep,a1
- clr.l d0
- }
- }
-
- diddleZoom(WindowPeek wPtr)
- {
- register short nLines, v, h;
- PEHandle hPE;
- long selStart, selEnd;
- short startLine, endLine;
- short i;
- register ExtWStateData *p;
- EventRecord e;
- EvQElPtr q;
- Rect curBounds;
- short newTop;
-
- if (!EqualString(CurApName, "\pTHINK C", FALSE, FALSE)) {
- SysBeep(1);
- return;
- }
-
- if (wPtr->dataHandle == 0 || (wPtr->windowKind != 0x0B && wPtr->windowKind != 0x0C))
- return;
-
- SetPort(wPtr);
- /* Rescue the PEHandle. This is slightly proprietary, but others have figured it
- * out, so what's the big deal?
- */
- hPE = *(PEHandle *)(4 + *(Handle)wPtr->refCon);
-
- /* This is all PE stuff, of course, similar to TE. I wish I could put in some
- * propaganda about buying Capps`, since I worked on the package, but since it's
- * not on the market anymore <<sigh>> it'll just frustrate you. I'll explain the
- * logic, since this FKEY is fairly adaptable to TE-based editors
- */
-
- /* Get the start line and end line of the selection. The minimum size of
- * a THINK C window is seven lines, so we adjust the startLine and number of
- * lines
- */
-
- /* PELineNum returns the line number of a character */
- startLine = PELineNum((**hPE).selStart, hPE);
- if (startLine > (**hPE).nLines - MINLINES)
- startLine = (**hPE).nLines - MINLINES;
- endLine = PELineNum((**hPE).selEnd, hPE);
- nLines = 2 + endLine - startLine;
- if (nLines < MINLINES)
- nLines = MINLINES;
-
- /* Figure out the new upper left corner of the window */
-
- newTop = 23 + (**hPE).lineHeight * (startLine - (**hPE).viewOrgV);
-
- /* I just figured out VMARGIN by varying it. It seem to be about right */
- v = nLines * (**hPE).lineHeight + VMARGIN;
-
- /* The fun part -- figuring out the longest selected line. This is really the
- * reason we need PE–specific stuff, since the selected lines might be possible
- * to figure out heuristically.
- */
- for (i = startLine; i <= endLine; i++) {
- long charno, eol;
- short len;
-
- /* PECharPos returns the first character on a line (i, in this case) */
- charno = PECharPos(i, hPE);
- /* PEEol returns the last character on the line that character charno is on */
- eol = PEEol(charno, hPE);
- /* PEOffsetH returns the pixel offset to a character */
- len = PEOffsetH(eol, hPE);
- if (h < len)
- h = len;
- }
- h += 20;
-
- /* Since we're called "ShrinkToFit", we don't really want to *grow* the window,
- * so limit the size to the current one
- */
- curBounds = ((WindowPtr)wPtr)->portRect;
- if (h > curBounds.right - curBounds.left)
- h = curBounds.right - curBounds.left;
- if (v > curBounds.bottom - curBounds.top)
- v = curBounds.bottom - curBounds.top;
-
- /* We're going to extend the dataHandle to include the old stdState (fully-zoomed
- * size), so that we can set it back after the window is resized
- */
- SetHandleSize(wPtr->dataHandle, sizeof(ExtWStateData));
- p = *(ExtWStateData **) wPtr->dataHandle;
-
- /* Shrink it using the old upper-left hand corner. It would probably be more
- * elegant to tile the suckers, but I don't feel like doing it right now
- */
- p->theUsual.userState.right = p->theUsual.userState.left + h;
- p->theUsual.userState.bottom = p->theUsual.userState.top + v;
- #if 0
- OffsetRect(&p->theUsual.userState, 0, newTop);
- #endif
-
- p->oldStdState = p->theUsual.stdState;
- p->theUsual.stdState = curBounds;
- LocalToGlobal(&topLeft(p->theUsual.stdState));
- LocalToGlobal(&botRight(p->theUsual.stdState));
- }